﻿using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using System.Collections.Generic;

using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Geodatabase;
using CartoLab.ShortestPath;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.DataSourcesRaster;
using CartoLab.GeometryLib.Geometries;
using System.Threading;
using System.Text;


namespace TrafficAccessibilityIndex
{

    public sealed partial class MainForm : Form
    {
        /// <summary>
        /// CPU内核数目
        /// </summary>
        private static int CPU_CORE_COUNT = 8;

        #region class private members
        private IMapControl3 m_mapControl = null;
        private string m_mapDocumentName = string.Empty;
        private StreamWriter sw = null;//重力模型中的保存网络距离文件流
        #endregion

        #region class constructor
        public MainForm()
        {
            InitializeComponent();
        }
        #endregion

        private void MainForm_Load(object sender, EventArgs e)
        {
            //get the MapControl
            m_mapControl = (IMapControl3)axMapControl1.Object;

            //disable the Save menu (since there is no document yet)
            menuSaveDoc.Enabled = false;
        }

        #region Main Menu event handlers
        private void menuNewDoc_Click(object sender, EventArgs e)
        {
            //execute New Document command
            ICommand command = new CreateNewDocument();
            command.OnCreate(m_mapControl.Object);
            command.OnClick();
        }

        private void menuOpenDoc_Click(object sender, EventArgs e)
        {
            //execute Open Document command
            ICommand command = new ControlsOpenDocCommandClass();
            command.OnCreate(m_mapControl.Object);
            command.OnClick();
        }

        private void menuSaveDoc_Click(object sender, EventArgs e)
        {
            //execute Save Document command
            if (m_mapControl.CheckMxFile(m_mapDocumentName))
            {
                //create a new instance of a MapDocument
                IMapDocument mapDoc = new MapDocumentClass();
                mapDoc.Open(m_mapDocumentName, string.Empty);

                //Make sure that the MapDocument is not readonly
                if (mapDoc.get_IsReadOnly(m_mapDocumentName))
                {
                    MessageBox.Show("Map document is read only!");
                    mapDoc.Close();
                    return;
                }

                //Replace its contents with the current map
                mapDoc.ReplaceContents((IMxdContents)m_mapControl.Map);

                //save the MapDocument in order to persist it
                mapDoc.Save(mapDoc.UsesRelativePaths, false);

                //close the MapDocument
                mapDoc.Close();
            }
        }

        private void menuSaveAs_Click(object sender, EventArgs e)
        {
            //execute SaveAs Document command
            ICommand command = new ControlsSaveAsDocCommandClass();
            command.OnCreate(m_mapControl.Object);
            command.OnClick();
        }

        private void menuExitApp_Click(object sender, EventArgs e)
        {
            //exit the application
            Application.Exit();
        }
        #endregion

        //listen to MapReplaced evant in order to update the statusbar and the Save menu
        private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
        {
            //get the current document name from the MapControl
            m_mapDocumentName = m_mapControl.DocumentFilename;

            //if there is no MapDocument, diable the Save menu and clear the statusbar
            if (m_mapDocumentName == string.Empty)
            {
                menuSaveDoc.Enabled = false;
                statusBarXY.Text = string.Empty;
            }
            else
            {
                //enable the Save manu and write the doc name to the statusbar
                menuSaveDoc.Enabled = true;
                statusBarXY.Text = System.IO.Path.GetFileName(m_mapDocumentName);
            }
        }

        private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
        {
            statusBarXY.Text = string.Format("{0}, {1}  {2}", e.mapX.ToString("#######.##"), e.mapY.ToString("#######.##"), axMapControl1.MapUnits.ToString().Substring(4));
        }
        private AnalysisType analysisType = AnalysisType.ByTime;



        private Dictionary<IFeature, Node> dicPoiFeatureNode = new Dictionary<IFeature, Node>();


        private List<Node> GetNodesOfCells(ILayer rasterLayer, List<Node> nodesList)
        {
            List<Node> result = new List<Node>();

            IRaster pRaster = (rasterLayer as IRasterLayer).Raster;

            IRasterProps rasterProps = (IRasterProps)pRaster;

            //设置栅格数据起始点  
            IPnt pBlockSize = new Pnt();
            pBlockSize.SetCoords(rasterProps.Width, rasterProps.Height);

            double dX = rasterProps.MeanCellSize().X; //栅格的宽度
            double dY = rasterProps.MeanCellSize().Y; //栅格的高度
            IEnvelope extent = rasterProps.Extent; //当前栅格数据集的范围

            //选取整个范围  
            IPixelBlock pPixelBlock = pRaster.CreatePixelBlock(pBlockSize);

            //左上点坐标  
            IPnt tlp = new Pnt();
            tlp.SetCoords(0, 0);

            //读入栅格  
            IRasterBandCollection pRasterBands = pRaster as IRasterBandCollection;
            IRasterBand pRasterBand = pRasterBands.Item(0);

            IRawPixels pRawRixels = pRasterBands.Item(0) as IRawPixels;

            pRawRixels.Read(tlp, pPixelBlock);

            //将PixBlock的值组成数组  
            System.Array pSafeArray = pPixelBlock.get_SafeArray(0) as System.Array;

            for (int y = 0; y < rasterProps.Height; y++)
            {
                for (int x = 0; x < rasterProps.Width; x++)
                {
                    //int value = Convert.ToInt32(pSafeArray.GetValue(x, y)); 
                    object oo = pSafeArray.GetValue(x, y);
                    double value = -1;
                    double.TryParse(oo.ToString(), out value);
                    if (value > 0)
                    {
                        Node node = GetNearestNode(x, y, pRaster, nodesList,
                                                       extent, dX, dY);
                        if (!result.Contains(node))
                        {
                            result.Add(node);
                        }
                    }
               }
            }

            return result;
        }

        /// <summary>
        /// 以栅格为单位计算每个栅格单元距离最近的医院、学校、之类的
        /// </summary>
        /// <param name="rasterLayer"></param>
        /// <param name="poiLayer"></param>
        private void CalculateTrafficeValue(ILayer rasterLayer,ILayer poiLayer,ILayer pointLayer)
        {
            string statusTxt = System.IO.Path.Combine(Application.StartupPath, DateTime.Now.Ticks + "计算结果.txt");
            
            IRaster pRaster = (rasterLayer as IRasterLayer).Raster;
            IRaster2 rst2First = (rasterLayer as IRasterLayer).Raster as IRaster2;
            IRasterProps rasterProps = (IRasterProps)pRaster;
            int cellcounts = (pointLayer as IFeatureLayer).FeatureClass.FeatureCount(null);
            //设置栅格数据起始点  
            IPnt pBlockSize = new Pnt();
            pBlockSize.SetCoords(rasterProps.Width, rasterProps.Height);

            double dX = rasterProps.MeanCellSize().X; //栅格的宽度
            double dY = rasterProps.MeanCellSize().Y; //栅格的高度
            IEnvelope extent = rasterProps.Extent; //当前栅格数据集的范围
            
            //选取整个范围  
            IPixelBlock pPixelBlock = pRaster.CreatePixelBlock(pBlockSize);

            //左上点坐标  
            IPnt tlp = new Pnt();
            tlp.SetCoords(0, 0);

            //读入栅格  
            IRasterBandCollection pRasterBands = pRaster as IRasterBandCollection;
            IRasterBand pRasterBand = pRasterBands.Item(0);

            IRawPixels pRawRixels = pRasterBands.Item(0) as IRawPixels;

            pRawRixels.Read(tlp, pPixelBlock);

            //将PixBlock的值组成数组  
            System.Array pSafeArray = pPixelBlock.get_SafeArray(0) as System.Array;

                StreamWriter sw = new StreamWriter(statusTxt);
                //if (File.Exists(statusTxt))
                //{
                //    sw = new StreamWriter(statusTxt, true);
                //}
                
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < cellcounts; i++)
                {
                    //int value = Convert.ToInt32(pSafeArray.GetValue(x, y)); 
                    System.Windows.Forms.Application.DoEvents();
                    IFeature f = (pointLayer as IFeatureLayer).FeatureClass.GetFeature(i);
                    IPoint p = f.Shape as IPoint;
                    int y = rst2First.ToPixelRow(p.Y);
                    int x = rst2First.ToPixelColumn(p.X);

                    object oo = pSafeArray.GetValue(x, y);
                    double value = -1;
                    double.TryParse(oo.ToString(), out value);
                    if (value >=-1)
                    {
                        double newValue = CalcNewValue(x, y, pRaster, poiLayer,
                                                       extent, dX, dY);

                        //pSafeArray.SetValue((Byte)(newValue), x, y);
                        pSafeArray.SetValue((float)newValue, x, y);
                        oo = pSafeArray.GetValue(x, y);
                    }

                    //string str = "行：" + y + "   列：" + x;
                    string str = "共"+cellcounts+"个栅格，正在处理第"+(i+1)+"个。";
                    this.statusBarXY.Text = str;
                    sb.Append(DateTime.Now.ToString() + "  " +str);
                    if (x % 100 == 0)
                    {
                        Application.DoEvents();
                    }
                }
                sw.WriteLine(sb.ToString());
                sw.Close();
                sw.Dispose();

            
            pPixelBlock.set_SafeArray(0, pSafeArray);

            //编辑raster，将更新的值写入raster中  
            IRasterEdit rasterEdit = pRaster as IRasterEdit;
            rasterEdit.Write(tlp, pPixelBlock);
            rasterEdit.Refresh(); 
        }

        /// <summary>
        ///计算栅格图层的最短路径
        /// </summary>
        /// <param name="rasterLayer">栅格图层</param>
        /// <param name="poiLayer">POI图层</param>
        private void CalculateTrafficeValue(IRasterLayer rasterLayer, ILayer poiLayer)
        {
            string statusTxt = System.IO.Path.Combine(Application.StartupPath, DateTime.Now.Ticks + "计算结果.txt");

            IRaster pRaster = (rasterLayer as IRasterLayer).Raster;
            IRaster2 rst2First = (rasterLayer as IRasterLayer).Raster as IRaster2;
            IRasterProps rasterProps = (IRasterProps)pRaster;
            double width = rasterProps.Width;
            double height = rasterProps.Height;
            //设置栅格数据起始点  
            IPnt pBlockSize = new Pnt();
            pBlockSize.SetCoords(rasterProps.Width, rasterProps.Height);

            double dX = rasterProps.MeanCellSize().X; //栅格的宽度
            double dY = rasterProps.MeanCellSize().Y; //栅格的高度
            IEnvelope extent = rasterProps.Extent; //当前栅格数据集的范围

            //选取整个范围  
            IPixelBlock pPixelBlock = pRaster.CreatePixelBlock(pBlockSize);

            //左上点坐标  
            IPnt tlp = new Pnt();
            tlp.SetCoords(0, 0);

            //读入栅格  
            IRasterBandCollection pRasterBands = pRaster as IRasterBandCollection;
            IRasterBand pRasterBand = pRasterBands.Item(0);

            IRawPixels pRawRixels = pRasterBands.Item(0) as IRawPixels;

            pRawRixels.Read(tlp, pPixelBlock);

            //将PixBlock的值组成数组  
            System.Array pSafeArray = pPixelBlock.get_SafeArray(0) as System.Array;

            StreamWriter sw = new StreamWriter(statusTxt);
            //if (File.Exists(statusTxt))
            //{
            //    sw = new StreamWriter(statusTxt, true);
            //}

            StringBuilder sb = new StringBuilder();
            int times = 0;
            string str = "当前影像分辨率为:" + height + "×" + width;
            for (int i = 0; i < height; ++i)
            {
                for (int j = 0; j < width; ++j)
                {
                    times++;
                    if (times >= 500)
                    {
                        this.statusBarXY.Text = str + ";正在处理第" + (i + 1) + "行,第" + (j + 1) + "列";
                        System.Windows.Forms.Application.DoEvents();
                        times = 0;
                    }
                    object oo = pSafeArray.GetValue(j, i);
                    double value = -1;
                    double.TryParse(oo.ToString(), out value);
                    if (value > -1)
                    {
                        double newValue = CalcNewValue(j, i, pRaster, poiLayer,
                                                       extent, dX, dY);
                        pSafeArray.SetValue((float)newValue, j, i);
                        oo = pSafeArray.GetValue(j, i);
                    }
                }
            }
            sw.WriteLine(sb.ToString());
            sw.Close();
            sw.Dispose();


            pPixelBlock.set_SafeArray(0, pSafeArray);

            //编辑raster，将更新的值写入raster中  
            IRasterEdit rasterEdit = pRaster as IRasterEdit;
            rasterEdit.Write(tlp, pPixelBlock);
            rasterEdit.Refresh();
        }

        /// <summary>
        /// 计算矢量图层的最短路径
        /// </summary>
        /// <param name="rasterLayer"></param>
        /// <param name="poiLayer"></param>
        private void CalculateTrafficeValue(IFeatureLayer pointLayer, ILayer poiLayer)
        {
            string fieldName = "";
            if (poiLayer.Name.Length > 8)
                fieldName = poiLayer.Name.Substring(0, 8);
            else
                fieldName = poiLayer.Name;
            IFeatureLayer featureLayer=pointLayer as IFeatureLayer;
            int IDIndex1 = featureLayer.FeatureClass.FindField(fieldName);
            int IDIndex2 = featureLayer.FeatureClass.FindField(fieldName + "ID");


            string statusTxt = System.IO.Path.Combine(Application.StartupPath, DateTime.Now.Ticks + "计算结果.txt");


            int cellcounts = featureLayer.FeatureClass.FeatureCount(null);

            StreamWriter sw = new StreamWriter(statusTxt);
            //if (File.Exists(statusTxt))
            //{
            //    sw = new StreamWriter(statusTxt, true);
            //}


            StringBuilder sb = new StringBuilder();
            int i = 0;
            IFeatureCursor feautureCursor = featureLayer.FeatureClass.Search(null, false);
            IFeature f= feautureCursor.NextFeature();
            while(f!=null)
            {
                //System.Windows.Forms.Application.DoEvents();
                IPoint p = null;
                if(f.Shape.GeometryType==esriGeometryType.esriGeometryPoint)
                    p=f.Shape as IPoint;
                else if(esriGeometryType.esriGeometryPolygon==f.Shape.GeometryType)
                {
                    IArea area = f.Shape as IArea;
                    p = area.Centroid;
                }
                int shortDisPOIID = -1;
                 double newValue = CalcNewValue(p, poiLayer,ref shortDisPOIID);

                f.set_Value(IDIndex1, newValue);
                f.set_Value(IDIndex2, shortDisPOIID);
                f.Store();
                //string str = "行：" + y + "   列：" + x;

                if (i % 10 == 0)
                {
                    Application.DoEvents();
                    GC.Collect();
                    string str = "共" + cellcounts + "个栅格，正在处理第" + (i + 1) + "个。";
                    this.statusBarXY.Text = str;
                    sb.Append(DateTime.Now.ToString() + "  " + str);
                }

                i++;
                f = feautureCursor.NextFeature();
            }
            sw.WriteLine(sb.ToString());
            sw.Close();
            sw.Dispose();
        }

        private void CalculateTrafficeValueToTxt(ILayer rasterLayer, ILayer poiLayer1, ILayer poiLayer2, ILayer poiLayer3, ILayer pointLayer)
        {
            string statusTxt = System.IO.Path.Combine(Application.StartupPath, "计算结果" + poiLayer1.Name + ".txt");

            IRaster pRaster = (rasterLayer as IRasterLayer).Raster;
            IRaster2 rst2First = (rasterLayer as IRasterLayer).Raster as IRaster2;
            IRasterProps rasterProps = (IRasterProps)pRaster;
            int cellcounts = (pointLayer as IFeatureLayer).FeatureClass.FeatureCount(null);
            //设置栅格数据起始点  
            IPnt pBlockSize = new Pnt();
            pBlockSize.SetCoords(rasterProps.Width, rasterProps.Height);

            double dX = rasterProps.MeanCellSize().X; //栅格的宽度
            double dY = rasterProps.MeanCellSize().Y; //栅格的高度
            IEnvelope extent = rasterProps.Extent; //当前栅格数据集的范围

            //选取整个范围  
            IPixelBlock pPixelBlock = pRaster.CreatePixelBlock(pBlockSize);

            //左上点坐标  
            IPnt tlp = new Pnt();
            tlp.SetCoords(0, 0);

            //读入栅格  
            IRasterBandCollection pRasterBands = pRaster as IRasterBandCollection;
            IRasterBand pRasterBand = pRasterBands.Item(0);

            IRawPixels pRawRixels = pRasterBands.Item(0) as IRawPixels;

            pRawRixels.Read(tlp, pPixelBlock);

            //将PixBlock的值组成数组  
            System.Array pSafeArray = pPixelBlock.get_SafeArray(0) as System.Array;
            if (File.Exists(statusTxt))
            {
                File.Delete(statusTxt);
            }
            System.IO.FileStream fs = new System.IO.FileStream(statusTxt, FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(fs);
            
            for (int i = 0; i < cellcounts; i++)
            {
                System.Windows.Forms.Application.DoEvents();
                IFeature f = (pointLayer as IFeatureLayer).FeatureClass.GetFeature(i);
                IPoint p = f.Shape as IPoint;
                int y = rst2First.ToPixelRow(p.Y);
                int x = rst2First.ToPixelColumn(p.X);
                    double value = CalcNewValue(p, poiLayer1,
                                                   extent, dX, dY);
                    value += CalcNewValue(p, poiLayer2,
                                                   extent, dX, dY);
                    value += CalcNewValue(p, poiLayer3,
                               extent, dX, dY);
                    string sb = y.ToString() + "_" + x.ToString() + " " + value.ToString();
                    if (i % 100 == 0)
                        GC.Collect();
                    string str = "行：" + y + "   列：" + x;
                    this.statusBarXY.Text = str;
                    sw.WriteLine(sb);
            }
            sw.Close();
            sw.Dispose();
            fs.Close();
            fs.Close();
           
        }

        private void MatchPoiNode(ILayer poiLayer, List<Node> nodesList)
        {
            IFeatureLayer feaLayer = poiLayer as IFeatureLayer;
            IFeatureCursor cursor = feaLayer.FeatureClass.Search(null, false);
            IFeature feature = cursor.NextFeature();
            while (feature != null)
            {
                IPoint pt = feature.Shape as IPoint;

                dicPoiFeatureNode.Add(feature, GetNearestNode(pt, nodesList));
                feature = cursor.NextFeature();
            }
        }

        private Node GetNearestNode(IPoint pt, List<Node> nodesList)
        {
            return GetNearestNode(pt.X, pt.Y, nodesList);
        }

        private Node GetNearestNode(double x,double y, List<Node> nodesList)
        {
            Node result = nodesList[0];
            double min = double.MaxValue;
            Coordinate cd = new Coordinate(x, y);
            foreach (Node node in nodesList)
            {
                double distance = cd.Distance(node.Postition);
                if (min > distance)
                {
                    min = distance;
                    result = node;
                }
            }
            return result;
        }

        private Node GetNearestNode(int x, int y, IRaster raster,
                                    List<Node> nodesList, IEnvelope extent,
                                     double dX, double dY)
        {
            //the point of top-left
            double imageX = extent.UpperLeft.X;
            double imageY = extent.UpperLeft.Y;

            double centerX = imageX + dX * x;
            double centerY = imageY - dY * y;

            //当前栅格单元的中心点坐标
            Coordinate cdRasterCell = new Coordinate(centerX, centerY);

            //离栅格单元最近的端点
            Node nodeRasterCell = GetNearestNode(centerX, centerY, nodesList);

            return nodeRasterCell;
        }

        private double CalcNewValue(int x, int y, IRaster raster,
                                    ILayer poiLayer, IEnvelope extent, 
                                     double dX, double dY)
        {
            string weightName = "Length";
            if (analysisType == AnalysisType.ByLength)
            {
                weightName = "Length";
            }
            else if (analysisType == AnalysisType.ByTime)
            {
                weightName = "ServiceTime";
            }

            //the point of top-left
            double imageX = extent.UpperLeft.X;
            double imageY = extent.UpperLeft.Y;

            double centerX = imageX + dX * x;
            double centerY = imageY - dY * y;

           //当前栅格单元的中心点坐标
           // Coordinate cdRasterCell = new Coordinate(centerX, centerY);
            IPoint ptCell = new PointClass();
            ptCell.X = centerX;
            ptCell.Y = centerY;

            double baseDistance = 100;

            ISpatialFilter spatialFilter = new SpatialFilterClass();
            spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
            spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

            IFeatureCursor cursor = (poiLayer as IFeatureLayer).Search(spatialFilter, false);
            IFeature feature = cursor.NextFeature();
            while (feature == null)
            {
                baseDistance += 100;
                spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
                spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

                cursor = (poiLayer as IFeatureLayer).Search(spatialFilter, false);
                feature = cursor.NextFeature();
            }


            double min = double.MaxValue;

            Dictionary<IFeature, double> dicPoiLength = new Dictionary<IFeature, double>();

            IPoint ptNearestCell = null;

            int loop = 0;
            IPoint ptNearestPOI = null;
            while (feature != null)
            {
                IPoint ptPoi = feature.Shape as IPoint;

                ptsForFindPath = new MultipointClass();

                m_pathFinder.StopPoints = ptsForFindPath;
                double[] EdgePercent = new double[2];
                int[] intEdgeIDS = new int[2];
                IPoint[] startEndPts = new IPoint[2];
                object o = Type.Missing;
                int intEdgeID = int.MinValue;

                double dblEdgePercent = double.MinValue;
                double tmpDis = 0;
                IPoint ipFoundEdgePoint = null;
                m_pathFinder.m_ipPointToEID.GetNearestEdge(ptCell, out intEdgeID, out ipFoundEdgePoint, out dblEdgePercent);
                if (ipFoundEdgePoint == null)
                {
                    ipFoundEdgePoint = GetNearestJounctionPoint(ptCell);
                    m_pathFinder.m_ipPointToEID.GetNearestEdge(ipFoundEdgePoint, out intEdgeID, out ipFoundEdgePoint, out dblEdgePercent);
                }
                intEdgeIDS[0] = intEdgeID;
                EdgePercent[0] = dblEdgePercent;
                startEndPts[0] = ipFoundEdgePoint;
                tmpDis += Math.Sqrt((ptCell.X - ipFoundEdgePoint.X) * (ptCell.X - ipFoundEdgePoint.X) +
                         (ptCell.Y - ipFoundEdgePoint.Y) * (ptCell.Y - ipFoundEdgePoint.Y));
                ptsForFindPath.AddPoint(ipFoundEdgePoint, ref o, ref o);

                IPoint ipFoundEdgePoint1 = null;
                intEdgeID = int.MinValue;

                dblEdgePercent = double.MinValue;
                m_pathFinder.m_ipPointToEID.GetNearestEdge(ptPoi, out intEdgeID, out ipFoundEdgePoint1, out dblEdgePercent);
                if (ipFoundEdgePoint1 == null)
                {
                    ipFoundEdgePoint1 = GetNearestJounctionPoint(ptCell);
                    m_pathFinder.m_ipPointToEID.GetNearestEdge(ipFoundEdgePoint1, out intEdgeID, out ipFoundEdgePoint1, out dblEdgePercent);
                }
                intEdgeIDS[1] = intEdgeID;
                EdgePercent[1] = dblEdgePercent;
                startEndPts[1] = ipFoundEdgePoint1;
                tmpDis += Math.Sqrt((ptPoi.X - ipFoundEdgePoint1.X) * (ptPoi.X - ipFoundEdgePoint1.X) +
                         (ptPoi.Y - ipFoundEdgePoint1.Y) * (ptPoi.Y - ipFoundEdgePoint1.Y));
                ptsForFindPath.AddPoint(ipFoundEdgePoint1, ref o, ref o);

                try
                {

                    int id = m_pathFinder.SolvePath(weightName, intEdgeIDS, EdgePercent);
                    #region 不需要显示路径
                    //IPolyline shortestPathLine = m_pathFinder.PathPolyLine(startEndPts);//返回最短路径
                    // if(shortestPathLine!=null)
                    //{
                    //    axMapControl1.ActiveView.Extent = shortestPathLine.Envelope;
                    //    axMapControl1.FlashShape(shortestPathLine as IGeometry);
                    //    Application.DoEvents();
                    //    axMapControl1.Refresh();
                    //}
                    // shortestPathLine.SetEmpty();
                    #endregion

                    double cost = m_pathFinder.PathCost + tmpDis;
                    double distance = Math.Sqrt((ipFoundEdgePoint.X - ipFoundEdgePoint1.X) * (ipFoundEdgePoint.X - ipFoundEdgePoint1.X) +
                                                 (ipFoundEdgePoint.Y - ipFoundEdgePoint1.Y) * (ipFoundEdgePoint.Y - ipFoundEdgePoint1.Y)) + tmpDis;
                    if (cost < distance)
                    {
                        if (analysisType == AnalysisType.ByLength)
                        {
                            cost = distance;
                        }
                        else if (analysisType == AnalysisType.ByTime)
                        {
                            cost = distance * 60 / 1000 / 25;
                        }
                    }

                    //double length = shortestPathLine.Length;
                    if (cost > -1 && min > cost)
                    {
                        min = cost;
                    }

                    dicPoiLength.Add(feature, cost);


                    ptsForFindPath.SetEmpty();
                }
                catch (Exception ex)
                {

                }
                ++loop;
                feature = cursor.NextFeature();
            }
            dicPoiLength.Clear();
           
            if (min == 0)
            {
                int m = 99;
            }
            return min;

            ////离栅格单元最近的端点
            //Node nodeRasterCell = GetNearestNode(centerX, centerY, nodesList);

            //double distance = 0;
            ////离栅格单元最近的POI
            //Node nodeNearestPOI = GetNearestPOI(nodeRasterCell, ref distance);
            //return distance;
        }

        private double CalcNewValue(IPoint ptCell,
                            ILayer poiLayer, IEnvelope extent,
                             double dX, double dY)
        {
            if (poiLayer == null)
                return 0;
            string weightName = "Length";
            if (analysisType == AnalysisType.ByLength)
            {
                weightName = "Length";
            }
            else if (analysisType == AnalysisType.ByTime)
            {
                weightName = "ServiceTime";
            }

            //the point of top-left
          
            double baseDistance = 100;

            ISpatialFilter spatialFilter = new SpatialFilterClass();
            spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
            spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;
            
            IFeatureCursor cursor = (poiLayer as IFeatureLayer).Search(spatialFilter, false);
            IFeature feature = cursor.NextFeature();
            while (feature == null)
            {
                baseDistance += 100;
                spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
                spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

                cursor = (poiLayer as IFeatureLayer).Search(spatialFilter, false);
                feature = cursor.NextFeature();
            }


            double min = double.MaxValue;

            Dictionary<IFeature, double> dicPoiLength = new Dictionary<IFeature, double>();

            IPoint ptNearestCell = null;

            int loop = 0;
            IPoint ptNearestPOI = null;
            while (feature != null)
            {
                IPoint ptPoi = feature.Shape as IPoint;

                ptsForFindPath = new MultipointClass();

                m_pathFinder.StopPoints = ptsForFindPath;

                object o = Type.Missing;
                ptsForFindPath.AddPoint(ptCell, ref o, ref o);
                ptsForFindPath.AddPoint(ptPoi, ref o, ref o);

                try
                {
                    int id = m_pathFinder.SolvePath(weightName);
                    double tmpDis = 0;
                    //先判断第一个节点
                    if (id == 0)
                    {
                        if (ptNearestCell == null)
                        {
                            ptNearestCell = GetNearestJounctionPoint(ptCell);
                        }
                        tmpDis += Math.Sqrt((ptCell.X - ptNearestCell.X) * (ptCell.X - ptNearestCell.X) +
                                                 (ptCell.Y - ptNearestCell.Y) * (ptCell.Y - ptNearestCell.Y));
                        ptCell = ptNearestCell;
                    }
                    else if (id == 1)
                    {
                        if (ptNearestCell == null)
                        {
                            ptNearestCell = GetNearestJounctionPoint(ptPoi);
                        }
                        tmpDis = Math.Sqrt((ptPoi.X - ptNearestCell.X) * (ptPoi.X - ptNearestCell.X) +
                         (ptPoi.Y - ptNearestCell.Y) * (ptPoi.Y - ptNearestCell.Y));
                        ptPoi = ptNearestCell;
                    }

                    if (id != -1)
                    {
                        ptsForFindPath = new MultipointClass();
                        m_pathFinder.StopPoints = ptsForFindPath;
                        ptsForFindPath.AddPoint(ptCell, ref o, ref o);
                        ptsForFindPath.AddPoint(ptPoi, ref o, ref o);
                        id = m_pathFinder.SolvePath(weightName);
                    }

                    //再判断第二个节点
                    if (id == 0)
                    {
                        if (ptNearestCell == null)
                        {
                            ptNearestCell = GetNearestJounctionPoint(ptCell);
                        }
                        tmpDis += Math.Sqrt((ptCell.X - ptNearestCell.X) * (ptCell.X - ptNearestCell.X) +
                                               (ptCell.Y - ptNearestCell.Y) * (ptCell.Y - ptNearestCell.Y));
                        ptCell = ptNearestCell;
                    }
                    else if (id == 1)
                    {
                        if (ptNearestCell == null)
                        {
                            ptNearestCell = GetNearestJounctionPoint(ptPoi);
                        }
                        tmpDis = Math.Sqrt((ptPoi.X - ptNearestCell.X) * (ptPoi.X - ptNearestCell.X) +
                      (ptPoi.Y - ptNearestCell.Y) * (ptPoi.Y - ptNearestCell.Y));
                        ptPoi = ptNearestCell;
                    }

                    if (id != -1)
                    {
                        ptsForFindPath = new MultipointClass();
                        m_pathFinder.StopPoints = ptsForFindPath;
                        ptsForFindPath.AddPoint(ptCell, ref o, ref o);
                        ptsForFindPath.AddPoint(ptPoi, ref o, ref o);
                        id = m_pathFinder.SolvePath(weightName);
                    }

                    IPolyline shortestPathLine = m_pathFinder.PathPolyLine();//返回最短路径
                    double cost = m_pathFinder.PathCost+tmpDis;
                    double distance = Math.Sqrt((ptCell.X - ptPoi.X) * (ptCell.X - ptPoi.X) +
                                                 (ptCell.Y - ptPoi.Y) * (ptCell.Y - ptPoi.Y))+tmpDis;
                    if (cost == 0)
                    {
                        if (analysisType == AnalysisType.ByLength)
                        {
                            cost = distance;
                        }
                        else if (analysisType == AnalysisType.ByTime)
                        {
                            cost = distance * 60 / 1000 / 25;
                        }
                    }
                    if (shortestPathLine != null)
                    {
                        //double length = shortestPathLine.Length;
                        if (cost > -1 && min > cost)
                        {
                            min = cost;
                            ptNearestPOI = m_pathFinder.StopPoints.get_Point(1);
                        }

                        dicPoiLength.Add(feature, cost);
                    }
                    shortestPathLine.SetEmpty();
                    ptsForFindPath.SetEmpty();
                }
                catch (Exception ex)
                {

                }
                ++loop;
                feature = cursor.NextFeature();
            }
            dicPoiLength.Clear();

            if (min == 0)
            {
                int m = 99;
            }
            return min;

            ////离栅格单元最近的端点
            //Node nodeRasterCell = GetNearestNode(centerX, centerY, nodesList);

            //double distance = 0;
            ////离栅格单元最近的POI
            //Node nodeNearestPOI = GetNearestPOI(nodeRasterCell, ref distance);
            //return distance;
        }


        private double CalcNewValue(IPoint ptCell,
                    ILayer poiLayer, ref int shortDisPOIID)
        {
            if (poiLayer == null)
                return 0;
            string weightName = "Length";
            if (analysisType == AnalysisType.ByLength)
            {
                weightName = "Length";
            }
            else if (analysisType == AnalysisType.ByTime)
            {
                weightName = "ServiceTime";
            }

            double baseDistance = 100;

            ISpatialFilter spatialFilter = new SpatialFilterClass();
            spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
            spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

            IFeatureCursor cursor = (poiLayer as IFeatureLayer).Search(spatialFilter, false);
            IFeature feature = cursor.NextFeature();
            while (feature == null)
            {
                baseDistance += 100;
                spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
                spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

                cursor = (poiLayer as IFeatureLayer).Search(spatialFilter, false);
                feature = cursor.NextFeature();
            }


            double min = double.MaxValue;

            Dictionary<IFeature, double> dicPoiLength = new Dictionary<IFeature, double>();

            //IPoint ptNearestCell = null;

            int loop = 0;
            //IPoint ptNearestPOI = null;


            while (feature != null)
            {
                IPoint ptPoi = feature.Shape as IPoint;

                ptsForFindPath = new MultipointClass();
                //m_pathFinder.PathCost = double.MaxValue;
                m_pathFinder.StopPoints = ptsForFindPath;
                double[] EdgePercent = new double[2];
                int[] intEdgeIDS = new int[2];
                IPoint[] startEndPts = new IPoint[2];
                object o = Type.Missing;
                int intEdgeID = int.MinValue;

                double dblEdgePercent = double.MinValue;
                double tmpDis = 0;
                IPoint ipFoundEdgePoint = null;
                m_pathFinder.m_ipPointToEID.GetNearestEdge(ptCell, out intEdgeID, out ipFoundEdgePoint, out dblEdgePercent);
                if (ipFoundEdgePoint==null)
                {
                    ipFoundEdgePoint = GetNearestJounctionPoint(ptCell);
                    m_pathFinder.m_ipPointToEID.GetNearestEdge(ipFoundEdgePoint, out intEdgeID, out ipFoundEdgePoint, out dblEdgePercent);
                }
                if(ipFoundEdgePoint==null)
                {
                    ptsForFindPath.SetEmpty();
                    min=double.MaxValue;
                    continue;
                }
                intEdgeIDS[0] = intEdgeID;
                EdgePercent[0] = dblEdgePercent;
                startEndPts[0] = ipFoundEdgePoint;
                tmpDis += Math.Sqrt((ptCell.X - ipFoundEdgePoint.X) * (ptCell.X - ipFoundEdgePoint.X) +
                         (ptCell.Y - ipFoundEdgePoint.Y) * (ptCell.Y - ipFoundEdgePoint.Y));
                ptsForFindPath.AddPoint(ipFoundEdgePoint, ref o, ref o);

                IPoint ipFoundEdgePoint1 = null;
                intEdgeID = int.MinValue;

                dblEdgePercent = double.MinValue;
                m_pathFinder.m_ipPointToEID.GetNearestEdge(ptPoi, out intEdgeID, out ipFoundEdgePoint1, out dblEdgePercent);
                if (ipFoundEdgePoint1 == null)
                {
                    ipFoundEdgePoint1 = GetNearestJounctionPoint(ptPoi);
                    m_pathFinder.m_ipPointToEID.GetNearestEdge(ipFoundEdgePoint1, out intEdgeID, out ipFoundEdgePoint1, out dblEdgePercent);
                }
                intEdgeIDS[1] = intEdgeID;
                EdgePercent[1] = dblEdgePercent;
                startEndPts[1] = ipFoundEdgePoint1;
                tmpDis += Math.Sqrt((ptPoi.X - ipFoundEdgePoint1.X) * (ptPoi.X - ipFoundEdgePoint1.X) +
                         (ptPoi.Y - ipFoundEdgePoint1.Y) * (ptPoi.Y - ipFoundEdgePoint1.Y));
                ptsForFindPath.AddPoint(ipFoundEdgePoint1, ref o, ref o);

                try
                {

                    int id = m_pathFinder.SolvePath(weightName,intEdgeIDS,EdgePercent);
                    #region 不需要显示路径
                    //IPolyline shortestPathLine = m_pathFinder.PathPolyLine(startEndPts);//返回最短路径
                    // if(shortestPathLine!=null)
                    //{
                    //    axMapControl1.ActiveView.Extent = shortestPathLine.Envelope;
                    //    axMapControl1.FlashShape(shortestPathLine as IGeometry);
                    //    Application.DoEvents();
                    //    axMapControl1.Refresh();
                    //}
                    // shortestPathLine.SetEmpty();
                     #endregion
                    double cost = 0;
                    if (m_pathFinder.PathCost ==0)
                        cost = Math.Sqrt((ipFoundEdgePoint.X - ipFoundEdgePoint1.X) * (ipFoundEdgePoint.X - ipFoundEdgePoint1.X) +
                                                 (ipFoundEdgePoint.Y - ipFoundEdgePoint1.Y) * (ipFoundEdgePoint.Y - ipFoundEdgePoint1.Y)) + tmpDis;
                    else
                        cost = m_pathFinder.PathCost + tmpDis;
                    //double distance = Math.Sqrt((ipFoundEdgePoint.X - ipFoundEdgePoint1.X) * (ipFoundEdgePoint.X - ipFoundEdgePoint1.X) +
                    //                             (ipFoundEdgePoint.Y - ipFoundEdgePoint1.Y) * (ipFoundEdgePoint.Y - ipFoundEdgePoint1.Y)) + tmpDis;
                    //if (cost <distance)
                    //{
                    //    if (analysisType == AnalysisType.ByLength)
                    //    {
                    //        cost = distance;
                    //    }
                    //    else if (analysisType == AnalysisType.ByTime)
                    //    {
                    //        cost = distance * 60 / 1000 / 25;
                    //    }
                    //}

                        //double length = shortestPathLine.Length;
                        if (cost > -1 && min > cost)
                        {
                            min = cost;
                            shortDisPOIID = feature.OID;
                            //ptNearestPOI = m_pathFinder.StopPoints.get_Point(1);
                        }

                       // dicPoiLength.Add(feature, cost);


                    ptsForFindPath.SetEmpty();
                }
                catch (Exception ex)
                {

                }
                ++loop;
                feature = cursor.NextFeature();
            }
            dicPoiLength.Clear();

            if (min == 0)
            {
                int m = 99;
            }
            return min;

            ////离栅格单元最近的端点
            //Node nodeRasterCell = GetNearestNode(centerX, centerY, nodesList);

            //double distance = 0;
            ////离栅格单元最近的POI
            //Node nodeNearestPOI = GetNearestPOI(nodeRasterCell, ref distance);
            //return distance;
        }

        private IPoint GetNearestJounctionPoint(IPoint ptCell)
        {
            ILayer layer = GetNetJunctionLayer();
            IFeatureLayer feaLayer = layer as IFeatureLayer;

            double baseDistance = 500;
            ISpatialFilter spatialFilter = new SpatialFilterClass();
            spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
            spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

            IFeatureCursor cursor = feaLayer.Search(spatialFilter, false);
            IFeature feature = cursor.NextFeature();
            while (feature == null)
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
                baseDistance += 1000;
                spatialFilter.Geometry = GetGeometry(ptCell, baseDistance);
                spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

                cursor = feaLayer.Search(spatialFilter, false);
                feature = cursor.NextFeature();
            }

            double min = double.MaxValue;
            IPoint result = null;
            while (feature != null)
            {
                IPoint pt = feature.Shape as IPoint;

                double distance = Math.Sqrt((ptCell.X - pt.X) * (ptCell.X - pt.X) +
                                             (ptCell.Y - pt.Y) * (ptCell.Y - pt.Y));
                if (min > distance)
                {
                    min = distance;
                    result = pt;
                }

                feature = cursor.NextFeature();
            }

            return result;
        }

        private IGeometry GetGeometry(IPoint pt, double distance)
        {
            ITopologicalOperator topolOperator = pt as ITopologicalOperator;
            return topolOperator.Buffer(distance);

        }

        private Node GetNearestPOI(Node nodeRasterCell, ref double distance)
        {
            double min = double.MaxValue;
            Node result = null;
            Dictionary<IFeature, Node>.ValueCollection  values = dicPoiFeatureNode.Values;
            foreach (Node nodePOI in values)
            {
                string key = nodeRasterCell.ID + "_" + nodePOI.ID;
                RoutePlanResult plan = null;
                if (dicRoutePlan.ContainsKey(key))
                {
                    plan = this.dicRoutePlan[key];
                }
                double d = -1;
                if (plan != null)
                {
                    d = this.dicPlanLength[plan];
                }
                if (d == -1)
                {
                    continue;
                }
                if (min > d)
                {
                    min = d;
                    result = nodePOI;
                }
            }
            distance = min;
            return result;
        }

        /// <summary>
        /// 所有路径的最短路径
        /// </summary>
        private Dictionary<string, RoutePlanResult> dicRoutePlan = 
                             new Dictionary<string, RoutePlanResult>();

        /// <summary>
        /// 所有最短路径的长度
        /// </summary>
        private Dictionary<RoutePlanResult, double> dicPlanLength =
                             new Dictionary<RoutePlanResult, double>();

        private void CalculateRoutePlan(List<Node> nodesList, List<Edge> edges, List<Node> nodesListOfCells)
        {

            //单线程版本

            //RoutePlanner planner = new RoutePlanner(nodesList.ToArray(),
            //                                        edges.ToArray());
            //dicRoutePlan.Clear();

            //int loop = 0;
            //foreach (Node node in nodesList)
            //{
            //    foreach (Node nodeEscape in dicPoiFeatureNode.Values)
            //    {
            //        RoutePlanResult plan = null;
            //        if (node.ID != nodeEscape.ID)
            //        {
            //            DateTime dtOld = DateTime.Now;
            //            plan = planner.Plan(node.ID, nodeEscape.ID);
            //            DateTime dtNow = DateTime.Now;
            //            TimeSpan s = dtNow - dtOld;
            //        }
            //        this.dicRoutePlan.Add(node.ID + "_" + nodeEscape.ID, plan);
            //    }
            //    ++loop;
            //}

            List<List<Node>> poiNodes = SplitPoiNodes();


            //多线程版本
            for (int index = 0; index < poiNodes.Count; ++index)
            {
                CalcShortestRouteParam param = new CalcShortestRouteParam(nodesList, edges,
                                                                          poiNodes[index], index,
                                                                          nodesListOfCells);

                Thread thread = new Thread(new ParameterizedThreadStart(CalcShortestRoute));
                thread.Name = " CalcShortestRoute_" + index;
                threadsList.Add(thread);
                thread.Start(param);
            }

            bool threadComplete = IsAllThreadsComplete(this.threadsList);
            while (!threadComplete)
            {
                threadComplete = IsAllThreadsComplete(this.threadsList);
            }

            CalculatePlanLength(edges);
        }

        private bool IsAllThreadsComplete(List<Thread> threads)
        {
            int loop = 0;
            foreach (Thread thread in threads)
            {
                if (thread.ThreadState != ThreadState.Stopped)
                {
                    return false;
                }
                ++loop;
            }
            return true;
        }

        private List<List<Node>> SplitPoiNodes()
        {
            //按照CPU核心数据划分成各个子部分
            int count = dicPoiFeatureNode.Values.Count / CPU_CORE_COUNT;

            List<Node> allNodes = new List<Node>();
            foreach (Node node in dicPoiFeatureNode.Values)
            {
                allNodes.Add(node);
            }

            List<List<Node>> result = new List<List<Node>>();
            if (count == 0)
            {
                result.Add(allNodes);
                return result;
            }


            int loop = 0;
            List<Node> group = new List<Node>();
            for (int i = 0; i < allNodes.Count; ++i)
            {
                if (loop ==0)
                {
                    group = new List<Node>();
                }
                if (loop == count)
                {
                    loop = 0;
                    result.Add(group);
                    continue;
                }
                group.Add(allNodes[i]);
                ++loop;
            }

            if (group.Count > 0)
            {
                result.Add(group);
            }

            return result;
        }

        private void CalcShortestRoute(object param)
        {
            CalcShortestRouteParam csrParam = param as CalcShortestRouteParam;

            Node[] allNodes = csrParam.NodesListOfCells.ToArray();//csrParam.NodesList.ToArray();
            Edge[] edges = csrParam.Edges.ToArray();
            Node[] subNodes = csrParam.SubNodesList.ToArray();

            RoutePlanner planner = new RoutePlanner(allNodes, edges);
            dicRoutePlan.Clear();

            int loop = 0;
            foreach (Node node in allNodes)
            {
                foreach (Node nodeEscape in subNodes)
                {
                    RoutePlanResult plan = null;
                    if (node.ID != nodeEscape.ID)
                    {
                        DateTime dtOld = DateTime.Now;
                        plan = planner.Plan(node.ID, nodeEscape.ID);
                        DateTime dtNow = DateTime.Now;
                        TimeSpan s = dtNow - dtOld;
                    }
                    this.dicRoutePlan.Add(node.ID + "_" + nodeEscape.ID, plan);
                }
                ++loop;
            }
            threadsList[csrParam.ThreadIndex].Abort();
        }


        private List<Thread> threadsList = new List<Thread>();

        private class CalcShortestRouteParam
        {
            private List<Node> nodesList;

            public List<Node> NodesList
            {
                get { return nodesList; }
                set { nodesList = value; }
            }
            private List<Edge> edges;

            public List<Edge> Edges
            {
                get { return edges; }
                set { edges = value; }
            }
            private List<Node> subNodesList;

            public List<Node> SubNodesList
            {
                get { return subNodesList; }
                set { subNodesList = value; }
            }

            public CalcShortestRouteParam(List<Node> _nodesList, List<Edge> _edges, 
                                          List<Node> _subNodesList, int _index,
                                          List<Node> _nodesListOfCells)
            {
                this.nodesList = _nodesList;
                this.edges = _edges;
                this.subNodesList = _subNodesList;
                this.ThreadIndex = _index;
                this.nodesListOfCells = _nodesListOfCells;
            }

            private int threadIndex = 0;
            private List<Node> nodesListOfCells;

            public List<Node> NodesListOfCells
            {
                get { return nodesListOfCells; }
                set { nodesListOfCells = value; }
            }

            public int ThreadIndex
            {
                get { return threadIndex; }
                set { threadIndex = value; }
            }

        }



        private void CalculatePlanLength(List<Edge> edges )
        {
            Dictionary<string, RoutePlanResult>.ValueCollection values = dicRoutePlan.Values;
            foreach (RoutePlanResult plan in values)
            {
                if (plan == null)
                {
                    continue;
                }
                double d = GetLength(plan,edges);
                this.dicPlanLength.Add(plan, d);
            }
        }

        private double GetLength(RoutePlanResult plan, List<Edge> edges)
        {
            double result = 0;
            string[] strs = plan.GetPassedNodeIDs();
            List<string> nodes = new List<string>();
            nodes.Add(plan.StartID);
            nodes.AddRange(strs);
            nodes.Add(plan.EndID);


            //Edge edge = FindEdge(plan.StartID, strs[0], edges);
            //if (edge != null)
            //{
            //    result += edge.Weight;
            //}


            //edge = FindEdge(plan.EndID, strs[strs.Length - 1], edges);
            //if (edge != null)
            //{
            //    result += edge.Weight;
            //}
            Edge edge = null;
            for (int i = 0; i < nodes.Count - 1; ++i)
            {
                edge = FindEdge(nodes[i], nodes[i + 1], edges);
                if (edge != null)
                {
                    result += edge.Weight;
                }
            }
            return result;
        }

        private Edge FindEdge(string startID, string endID, List<Edge> edges)
        {
            foreach (Edge edge in edges)
            {
                if (edge.StartNodeID == startID &&
                   edge.EndNodeID == endID)
                {
                    return edge;
                }
            }
            return null;
        }


        private void UpdateNodeEdgeRelation(Node[] nodes, Edge[] edges)
        {
            //把坐标相同，编号不同的node替换为同一个node
            foreach (Node node in nodes)
            {
                if (node.Postition == null)
                {
                    continue;
                }
                Node[] sameNodes = GetNodeSameCoordinate(node, nodes);

                Node nodeFirst = sameNodes[0];
                if (sameNodes.Length == 1)
                {
                    continue;
                }
                for (int i = 1; i < sameNodes.Length; ++i)
                {
                    Edge[] edgesRelatedNode = GetStartNodeRelatedEdges(sameNodes[i],
                                                                  edges);
                    foreach (Edge edge in edgesRelatedNode)
                    {
                        edge.StartNodeID = nodeFirst.ID;
                    }

                    edgesRelatedNode = GetEndNodeRelatedEdges(sameNodes[i],
                                                                  edges);
                    foreach (Edge edge in edgesRelatedNode)
                    {
                        edge.EndNodeID = nodeFirst.ID;
                    }

                    sameNodes[i].Postition = null;
                }
            }

            foreach (Node node in nodes)
            {
                Edge[] relationEdges = GetStartNodeRelatedEdges(node, edges);
                node.AddEdge(relationEdges);
            }
        }

        private Node[] GetNodeSameCoordinate(Node nodeTarget, Node[] nodes)
        {
            List<Node> result = new List<Node>();
            foreach (Node node in nodes)
            {
                if (node.Postition == null ||
                    nodeTarget.Postition == null)
                {
                    continue;
                }
                if (node.Postition.X == nodeTarget.Postition.X &&
                    node.Postition.Y == nodeTarget.Postition.Y)
                {
                    result.Add(node);
                }
            }
            return result.ToArray();
        }

        private Edge[] GetStartNodeRelatedEdges(Node node, Edge[] edges)
        {
            List<Edge> result = new List<Edge>();
            foreach (Edge edge in edges)
            {
                if (edge.StartNodeID == node.ID)
                {
                    result.Add(edge);
                }
            }
            return result.ToArray();
        }

        private Edge[] GetEndNodeRelatedEdges(Node node, Edge[] edges)
        {
            List<Edge> result = new List<Edge>();
            foreach (Edge edge in edges)
            {
                if (edge.EndNodeID == node.ID)
                {
                    result.Add(edge);
                }
            }
            return result.ToArray();
        }

        private List<Edge> CreateEdges(Dictionary<IFeature, double> featuresDic, 
                                       List<Node> nodesList)
        {
            int edgeLoop = 1;
            Dictionary<IFeature, double>.KeyCollection keys = featuresDic.Keys;

            List<Edge> result = new List<Edge>();
            foreach (IFeature feature in keys)
            {
                IPointCollection pts = feature.Shape as IPointCollection;
                int ptsCount = pts.PointCount;
                IPoint ptFirst = pts.get_Point(0);
                IPoint ptLast = pts.get_Point(ptsCount - 1);

                Node nodeFirst = FineNode(ptFirst, nodesList);
                if (nodeFirst == null)
                {
                    int m = 99;
                }
                Node nodeLast = FineNode(ptLast, nodesList);
                if (nodeLast == null)
                {
                    int m = 99;
                }

                Edge edge = new Edge(edgeLoop.ToString(), 
                                     nodeFirst.ID,
                                     nodeLast.ID, 
                                     featuresDic[feature]);
                result.Add(edge);

                ++edgeLoop;
                //双向通行，首尾要互反
                edge = new Edge(edgeLoop.ToString(), 
                                nodeLast.ID,
                                nodeFirst.ID,
                                featuresDic[feature]);
                result.Add(edge);


                ++edgeLoop;
            }

            return result;
        }

        private Node FineNode(IPoint pt, List<Node> nodesList)
        {
            CartoLab.GeometryLib.Geometries.Coordinate cd = 
                        new CartoLab.GeometryLib.Geometries.Coordinate(pt.X, pt.Y);
            foreach (Node node in nodesList)
            {
                if (node.Postition.Equals(cd))
                {
                    return node;
                }
            }
            return null;
        }

        private void CollectNodes(Node nodeFirst, Node nodeLast, List<Node> nodesList)
        {
            CollectNode(nodeFirst, nodesList);
            CollectNode(nodeLast, nodesList);
        }

        private void CollectNode(Node nodeTarget, List<Node> nodesList)
        {
            //相同坐标的点被视为是同一个点
            foreach (Node node in nodesList)
            {
                if (node.Postition.Equals(nodeTarget.Postition))
                {
                    return;
                }
            }
            nodesList.Add(nodeTarget);
        }

        private Node Point2Node(IPoint pt, int id)
        {
            CartoLab.GeometryLib.Geometries.Coordinate cd = new CartoLab.GeometryLib.Geometries.Coordinate(pt.X, pt.Y);
            return new Node(id.ToString(),cd);
        }

        private ClsPathFinder m_pathFinder = null;
        private void ToolStripMenuItemFindPath_Click(object sender, EventArgs e)
        {
            if (m_pathFinder == null)
            {
                m_pathFinder = new ClsPathFinder();
                IMap map = this.axMapControl1.ActiveView.FocusMap;
                ILayer lyr = GetNetJunctionLayer();
                IFeatureLayer feaLayer = lyr as IFeatureLayer;
                IFeatureDataset dataset = feaLayer.FeatureClass.FeatureDataset;
                m_pathFinder.SetOrGetMap = map;
                m_pathFinder.OpenFeatureDatasetNetwork(dataset);
            }
        }

        private ILayer GetNetJunctionLayer()
        {
            for (int i = 0; i < this.axMapControl1.Map.LayerCount; ++i)
            {
                ILayer layer = this.axMapControl1.Map.get_Layer(i);
                if (layer.Name.Contains("Junctions"))
                {
                    return layer;
                }
            }
            return null;
        }


        private MultipointClass ptsForFindPath = null;
        private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
        {
            if(!needAddPoint)
            {
                return;
            }
            IPoint ipNew;
            if (ptsForFindPath == null)
            {
                ptsForFindPath = new MultipointClass();
                m_pathFinder.StopPoints = ptsForFindPath;
            }
            ipNew = this.axMapControl1.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(e.x, e.y);
            object o = Type.Missing;
            ptsForFindPath.AddPoint(ipNew, ref o, ref o);    
        }

        private void ToolStripMenuItemFindpath_Click_1(object sender, EventArgs e)
        {

            IPoint pt1 = new PointClass();
            pt1.X = 100394;
            pt1.Y = 13001;

            IPoint pt2 = new PointClass();
            pt2.X =100451.985;
            pt2.Y = 13585.789;
            object o = Type.Missing;
            ptsForFindPath = new MultipointClass();
           m_pathFinder.StopPoints = ptsForFindPath;
            ptsForFindPath.AddPoint(pt1, ref o, ref o);

            ptsForFindPath.AddPoint(pt2, ref o, ref o);





            

            //m_pathFinder.SolvePath("Weight");//解析路径

            m_pathFinder.SolvePath("Length");

            IPolyline ipPolyResult = m_pathFinder.PathPolyLine();//返回最短路径


            //高亮显示结果
            HookHelperClass hookHelper = new HookHelperClass();
            hookHelper.Hook = axMapControl1.Object;
            IHookActions hookAction = hookHelper as IHookActions;
            hookAction.DoAction(ipPolyResult, esriHookActions.esriHookActionsFlash);


            //把找到的最短路径放到drawable中，便于绘制
           

        }

        private bool needAddPoint = false;
        private void ToolStripMenuItemAddPoint_Click(object sender, EventArgs e)
        {
            needAddPoint = !needAddPoint;
            this.ToolStripMenuItemAddPoint.Checked = needAddPoint;
        }

        private void ToolStripMenuItemClearPoints_Click(object sender, EventArgs e)
        {
            ptsForFindPath = new MultipointClass();
            m_pathFinder.StopPoints = ptsForFindPath;
        }

        private void 将最短路径保存到ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormParameters dlg = new FormParameters(this.axMapControl1);
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            //ILayer roadLayer = dlg.RoadLayer;
            ILayer rasterLayer = dlg.RasterLayer;
            ILayer poiLayer1 = dlg.POILayer1;
            ILayer poiLayer2 = dlg.POILayer2;
            ILayer poiLayer3 = dlg.POILayer3;
            ILayer pointLayer = dlg.POINTLayer;
            analysisType = dlg.AnalysisType;

            CalculateTrafficeValueToTxt(rasterLayer, poiLayer1, poiLayer2, poiLayer3, pointLayer);
            //Application.Exit();
            MessageBox.Show("计算完成");
        }

        private void 栅格数据最短路径ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RasterLayerForm dlg = new RasterLayerForm(this.axMapControl1);
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            //ILayer roadLayer = dlg.RoadLayer;
            ILayer rasterLayer = dlg.RasterLayer;
            ILayer poiLayer1 = dlg.POILayer1;
            analysisType = dlg.AnalysisType;

            //开始以栅格为单位计算每个栅格单元距离最近的医院、学校、之类的
            CalculateTrafficeValue(rasterLayer as IRasterLayer, poiLayer1);
            //Application.Exit();
            MessageBox.Show("计算完成");
        }

        private void 点图层ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FeatureLayerForm dlg = new FeatureLayerForm(this.axMapControl1);
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            //ILayer roadLayer = dlg.RoadLayer;

            ILayer poiLayer1 = dlg.POILayer1;

            ILayer pointLayer = dlg.POINTLayer;
            IFeatureClass fclass = (pointLayer as IFeatureLayer).FeatureClass;
            string fieldName = "";
            if (poiLayer1.Name.Length > 8)
                fieldName = poiLayer1.Name.Substring(0, 8);
            else
                fieldName = poiLayer1.Name;
            if (fclass.FindField(fieldName) == -1)
            {
                IField newField = new FieldClass();
                IFieldEdit fieldEdit = (IFieldEdit)newField;
                fieldEdit.Name_2 =fieldName;
                fieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;
                fclass.AddField(newField);
            }
            if (fclass.FindField(fieldName + "ID") == -1)
            {
                IField newField = new FieldClass();
                IFieldEdit fieldEdit = (IFieldEdit)newField;
                fieldEdit.Name_2 = fieldName + "ID";
                fieldEdit.Type_2 = esriFieldType.esriFieldTypeInteger;
                fclass.AddField(newField);
            }
            analysisType = dlg.AnalysisType;
            CalculateTrafficeValue(pointLayer as IFeatureLayer, poiLayer1);
            //Application.Exit();
            MessageBox.Show("计算完成");
        }

        private void 森林公园ToolStripMenuItem_Click(object sender, EventArgs e)
        {

            GravityModelForm dlg = new GravityModelForm(this.axMapControl1);
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            ILayer layer1 = dlg.FeatureLayer;
            ILayer layer2 = dlg.POILayer1;
            ILayer layer3 = dlg.JunctionLayer;
            ParkGravityModel pgm = new ParkGravityModel(layer1,layer2, layer3, m_pathFinder, this.statusBarXY);
            IFeatureClass fclass = (layer1 as IFeatureLayer).FeatureClass;
            string fieldName = "";
            if (layer2.Name.Length > 10)
                fieldName = layer2.Name.Substring(0, 10);
            else
                fieldName = layer2.Name;
            if (fclass.FindField(fieldName) == -1)
            {
                IField newField = new FieldClass();
                IFieldEdit fieldEdit = (IFieldEdit)newField;
                fieldEdit.Name_2 = fieldName;
                fieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;
                fclass.AddField(newField);
            }
            pgm.CalcLayerNetDistance(ref sw);
            pgm.CalcLayerAccessability();
            GC.Collect();
            MessageBox.Show("计算完成！");
        }

        private void Initialize_Click(object sender, EventArgs e)
        {
            if (m_pathFinder == null)
            {
                m_pathFinder = new ClsPathFinder();
                IMap map = this.axMapControl1.ActiveView.FocusMap;
                ILayer lyr = GetNetJunctionLayer();
                IFeatureLayer feaLayer = lyr as IFeatureLayer;
                IFeatureDataset dataset = feaLayer.FeatureClass.FeatureDataset;
                m_pathFinder.SetOrGetMap = map;
                m_pathFinder.OpenFeatureDatasetNetwork(dataset);
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(sw!=null)
                sw.Close();
            System.Diagnostics.Process p = System.Diagnostics.Process.GetCurrentProcess();
            p.Kill();
        }

        private void 城市公园ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GravityModelForm dlg = new GravityModelForm(this.axMapControl1);
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            ILayer layer1 = dlg.FeatureLayer;
            ILayer layer2 = dlg.POILayer1;
            ILayer layer3 = dlg.JunctionLayer;
            ParkGravityModel pgm = new ParkGravityModel(layer1, layer2, layer3, m_pathFinder, this.statusBarXY);
            IFeatureClass fclass = (layer1 as IFeatureLayer).FeatureClass;
            string fieldName = "";
            if (layer2.Name.Length > 10)
                fieldName = layer2.Name.Substring(0, 10);
            else
                fieldName = layer2.Name;
            if (fclass.FindField(fieldName) == -1)
            {
                IField newField = new FieldClass();
                IFieldEdit fieldEdit = (IFieldEdit)newField;
                fieldEdit.Name_2 = fieldName;
                fieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;
                fclass.AddField(newField);
            }
            pgm.CalcLayerNetDistance(ref sw);
            pgm.CalcLayerAccessability();
            GC.Collect();
            MessageBox.Show("计算完成！");
        }

        private void 社区公园ToolStripMenuItem_Click(object sender, EventArgs e)
        {

            GravityModelForm dlg = new GravityModelForm(this.axMapControl1);
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            ILayer layer1 = dlg.FeatureLayer;
            ILayer layer2 = dlg.POILayer1;
            ILayer layer3 = dlg.JunctionLayer;
            ParkGravityModel pgm = new ParkGravityModel(layer1, layer2, layer3, m_pathFinder, this.statusBarXY);
            IFeatureClass fclass = (layer1 as IFeatureLayer).FeatureClass;
            string fieldName = "";
            if (layer2.Name.Length > 10)
                fieldName = layer2.Name.Substring(0, 10);
            else
                fieldName = layer2.Name;
            if (fclass.FindField(fieldName) == -1)
            {
                IField newField = new FieldClass();
                IFieldEdit fieldEdit = (IFieldEdit)newField;
                fieldEdit.Name_2 = fieldName;
                fieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;
                fclass.AddField(newField);
            }
            pgm.CalcLayerNetDistance(ref sw);
            pgm.CalcLayerAccessability();
            GC.Collect();
            MessageBox.Show("计算完成！");
        }
    }
}